﻿namespace Home.Pipelines.Http
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Net.Http;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;

    internal abstract class BidHttpPipelineBase : BidPipelineBase
    {
        private CancellationToken cancellationToken;

        protected async virtual Task<BidHtmlContent> GetHtmlAsync(string uri, object httpHeaders = null)
        {
            Debug.Assert(!string.IsNullOrEmpty(uri));

            var response = await SendRequestAsync(uri, HttpMethod.Get, httpHeaders, null);
            return await ProcessHtmlResult(response);
        }

        protected async virtual Task<BidJsonContent> GetJsonAsync(string uri, object httpHeaders = null)
        {
            Debug.Assert(!string.IsNullOrEmpty(uri));

            var response = await SendRequestAsync(uri, HttpMethod.Get, httpHeaders, null);
            return await ProcessJsonResult(response);
        }

        protected async virtual Task<BidVerificationCodeContent> GetVerificationCodeAsync(string uri, object httpHeaders = null)
        {
            Debug.Assert(!string.IsNullOrEmpty(uri));

            var response = await SendRequestAsync(uri, HttpMethod.Get, httpHeaders, null);
            return await ProcessVerificationCodeResult(response);
        }

        protected async virtual Task<BidJsonContent> PostJsonAsync(string uri, BidJsonContent content, object httpHeaders = null)
        {
            Debug.Assert(!string.IsNullOrEmpty(uri));

            var body = content == null ? string.Empty : content.ToString();
            var response = await SendRequestAsync(uri, HttpMethod.Post, httpHeaders, new StringContent(body, Encoding.UTF8, "application/json"));
            return await ProcessJsonResult(response);
        }

        private async Task<HttpResponseMessage> SendRequestAsync(string uri, HttpMethod method, object headers, HttpContent body)
        {
            var result = default(HttpResponseMessage);

            var handler = new BidHttpMessageHandler(headers);
            using (var http = new HttpClient(handler, true))
            {
                if (method == HttpMethod.Get)
                {
                    await http.GetAsync(uri, this.cancellationToken);
                }
                else if (method == HttpMethod.Post)
                {
                    await http.PostAsync(uri, body, this.cancellationToken);
                }
            }

            try
            {
                result = result.EnsureSuccessStatusCode();
                return result;
            }
            catch (Exception ex)
            {
                throw new BidHttpException("The HTTP request was failed.{0}URI: {1}{0}HTTP Method: {2}{0}HTTP Headers: {3}{0}HTTP Content: {4}", ex, Environment.NewLine, uri, method, BidHttpHelper.ConvertObjectToHttpHeadersString(headers), BidHttpHelper.ConvertHttpContentToString(body));
            }
        }

        private static async Task<BidHtmlContent> ProcessHtmlResult(HttpResponseMessage response)
        {
            var html = await response.Content.ReadAsStringAsync();
            return new BidHtmlContent(html);
        }

        private static async Task<BidJsonContent> ProcessJsonResult(HttpResponseMessage response)
        {
            var json = await response.Content.ReadAsStringAsync();
            return new BidJsonContent(json);
        }

        private static async Task<BidVerificationCodeContent> ProcessVerificationCodeResult(HttpResponseMessage response)
        {
            var bytes = await response.Content.ReadAsByteArrayAsync();
            return new BidVerificationCodeContent(bytes);
        }
    }
}
